package com.panda.admin.gateway.until;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * author: tcy
 * createDate: 2023/3/16
 * description: redis工具类
 */
@Component
public class RedisUtils {

    Logger log = LoggerFactory.getLogger(RedisUtils.class);

    private final RedisTemplate<String, Object> redisTemplate;

    public RedisUtils(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }


    /****************************  String类型相关操作  *******************************************/

    /**
     * 指定缓存时效
     * @param key
     * @param time
     * @return
     */
    public boolean setExpire(String key, long time) {
        try {
            if (time > 0L) {
                this.redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            log.error("redisTemplate setExpire error: {}", e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取缓存时效
     * @param key
     * @return
     */
    public long getExpire(String key) {
        return this.redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * key是否存在
     * @param key
     * @return
     */
    public boolean hasKey(String key) {
        try {
            return this.redisTemplate.hasKey(key);
        } catch (Exception e) {
            log.error("redisTemplate hasKey error: {}", e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     * @param key
     */
    public void delete(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                this.redisTemplate.delete(key[0]);
            } else {
                this.redisTemplate.delete(CollectionUtils.arrayToList(key));
            }
        }

    }

    /**
     * 普通获取缓存
     * @param key
     * @return
     */
    public Object get(String key) {
        try {
            return key == null ? null : this.redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            log.error("redisTemplate get error: {}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 普通缓存放入
     * @param key
     * @param value
     * @return
     */
    public boolean set(String key, Object value) {
        try {
            this.redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            log.error("redisTemplate set error: {}", e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 普通缓存设置时效
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0L) {
                this.redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                this.set(key, value);
            }
            return true;
        } catch (Exception e) {
            log.error("redisTemplate set with time error: {}",e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

    /**
     * key不存在时缓存，存在时不执行
     * @param key
     * @param value
     * @return 已存在key值返回false
     */
    public boolean setIfAbsent(String key, String value){
        return this.redisTemplate.opsForValue().setIfAbsent(key, value);
    }

    /**
     * 递增
     * @param key
     * @param delta
     * @return
     */
    public long incr(String key, long delta) {
        try {
            if (delta < 0L) {
                throw new RuntimeException("递增因子必须大于0");
            } else {
                return this.redisTemplate.opsForValue().increment(key, delta);
            }
        }catch (Exception e){
            log.error("redisTemplate incr error: {}", e.getMessage());
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 递减
     * @param key
     * @param delta
     * @return
     */
    public long decr(String key, long delta) {
        try {
            if (delta < 0L) {
                throw new RuntimeException("递减因子必须大于0");
            } else {
                return this.redisTemplate.opsForValue().increment(key, -delta);
            }
        }catch (Exception e){
            log.error("redisTemplate decr error: {}", e.getMessage());
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /****************************  Hash类型相关操作  *******************************************/

    /**
     * 向hash表存数据，不存在直接创建
     * @param key
     * @param item
     * @param value
     * @return
     */
    public boolean hashSet(String key, String item, Object value) {
        try {
            this.redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向hash表存数据，不存在直接创建，设置时效
     * @param key
     * @param item
     * @param value
     * @param time
     * @return
     */
    public boolean hashSet(String key, String item, Object value, long time) {
        try {
            this.redisTemplate.opsForHash().put(key, item, value);
            if (time > 0L) {
                this.setExpire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取hash表数据
     * @param key
     * @param item
     * @return
     */
    public Object hashGet(String key, String item) {
        return this.redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 删除hash表数据
     * @param key
     * @param item
     */
    public void hashDelete(String key, Object... item) {
        this.redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表是否有该值
     * @param key
     * @param item
     * @return
     */
    public boolean hashHasKey(String key, String item) {
        return this.redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如不存在就创建，再返回新增值
     * @param key
     * @param item
     * @param by
     * @return
     */
    public double hashIncr(String key, String item, double by) {
        return this.redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     * @param key
     * @param item
     * @param by
     * @return
     */
    public double hashDecr(String key, String item, double by) {
        return this.redisTemplate.opsForHash().increment(key, item, -by);
    }

    /**
     * hash值为map
     * @param key
     * @param map
     * @return
     */
    public boolean hashMapSet(String key, Map<String, Object> map) {
        try {
            this.redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 获取值为map的hash
     * @param key
     * @return
     */
    public Map<Object, Object> hashMapGet(String key) {
        return this.redisTemplate.opsForHash().entries(key);
    }

    /**
     * hash值为map 设置时效
     * @param key
     * @param map
     * @param time
     * @return
     */
    public boolean hashMapSet(String key, Map<String, Object> map, long time) {
        try {
            this.redisTemplate.opsForHash().putAll(key, map);
            if (time > 0L) {
                this.setExpire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /****************************  Set类型相关操作  *******************************************/

    /**
     * set缓存
     * @param key
     * @param values
     * @return
     */
    public long sSet(String key, Object... values) {
        try {
            return this.redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * set缓存 设置时效
     * @param key
     * @param time
     * @param values
     * @return
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = this.redisTemplate.opsForSet().add(key, values);
            if (time > 0L) {
                this.setExpire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * set获取
     * @param key
     * @return
     */
    public Set<Object> getSet(String key) {
        try {
            return this.redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * set查询
     * @param key
     * @param value
     * @return
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return this.redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * set缓存长度
     * @param key
     * @return
     */
    public long sGetSize(String key) {
        try {
            return this.redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * set删除
     * @param key
     * @param values
     * @return
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = this.redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0L;
        }
    }

    /**
     * set随机获取变量中元素
     * @param key
     * @return
     */
    public Object setRandom(String key){
        try {
            return redisTemplate.opsForSet().randomMember(key);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }
    }

    /****************************  List类型相关操作  *******************************************/

    /**
     * 对象缓存
     * @param key
     * @param value
     * @return
     */
    public boolean setList(String key, Object value) {
        try {
            this.redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception var4) {
            var4.printStackTrace();
            return false;
        }
    }

    /**
     * 对象缓存 设置时效
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean setList(String key, Object value, long time) {
        try {
            this.redisTemplate.opsForList().rightPush(key, value);
            if (time > 0L) {
                this.setExpire(key, time);
            }
            return true;
        } catch (Exception var6) {
            var6.printStackTrace();
            return false;
        }
    }

    /**
     * list缓存
     * @param key
     * @param value
     * @return
     */
    public boolean setList(String key, List<Object> value) {
        try {
            this.redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * list缓存 设置时效
     * @param key
     * @param value
     * @param time
     * @return
     */
    public boolean setList(String key, List<Object> value, long time) {
        try {
            this.redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0L) {
                this.setExpire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * list获取
     * @param key
     * @return
     */
    public List<Object> getList(String key) {
        try {
            return this.redisTemplate.opsForList().range(key, 0L, -1L);
        } catch (Exception var3) {
            var3.printStackTrace();
            return null;
        }
    }

    /**
     * list获取  设置时间
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List<Object> getList(String key, long start, long end) {
        try {
            return this.redisTemplate.opsForList().range(key, start, end);
        } catch (Exception var7) {
            var7.printStackTrace();
            return null;
        }
    }

    /**
     * list缓存长度
     * @param key
     * @return
     */
    public long getListSize(String key) {
        try {
            return this.redisTemplate.opsForList().size(key);
        } catch (Exception var3) {
            var3.printStackTrace();
            return 0L;
        }
    }

    /**
     * 通过索引获取list
     * @param key
     * @param index
     * @return
     */
    public Object getListIndex(String key, long index) {
        try {
            return this.redisTemplate.opsForList().index(key, index);
        } catch (Exception var5) {
            var5.printStackTrace();
            return null;
        }
    }

    /**
     * 通过索引修改list
     * @param key
     * @param index
     * @param value
     * @return
     */
    public boolean updateListIndex(String key, long index, Object value) {
        try {
            this.redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception var6) {
            var6.printStackTrace();
            return false;
        }
    }

    /**
     * list删除
     * @param key
     * @param count
     * @param value
     * @return
     */
    public long listRemove(String key, long count, Object value) {
        try {
            Long remove = this.redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception var6) {
            var6.printStackTrace();
            return 0L;
        }
    }

    /****************************  ZSet类型相关操作  *******************************************/

    /**
     * 添加元素,有序集合是按照元素的score值由小到大排列
     * @param key 键
     * @param value 对象名称
     * @param score 数据值
     * @return
     */
    public Boolean zSet(String key, String value, double score) {
        return redisTemplate.opsForZSet().add(key, value, score);
    }

    /**
     * 添加元素 向集合中插入多个元素
     * @param key 键
     * @param values set集合
     * @return
     */
    public Long zSet(String key, Set<ZSetOperations.TypedTuple<Object>> values) {
        return redisTemplate.opsForZSet().add(key, values);
    }

    /**
     * 获取集合的元素, 从小到大排序
     * @param key
     * @param start 开始位置
     * @param end 结束位置, -1查询所有
     * @return
     */
    public Set<Object> zGet(String key, long start, long end) {
        return redisTemplate.opsForZSet().range(key, start, end);
    }

    /**
     * 从集合中删除指定元素
     * @param key 键
     * @param values
     * @return
     */
    public Long zDelete(String key, Object... values) {
        return redisTemplate.opsForZSet().remove(key, values);
    }

    /**
     * 增加元素的score值，并返回增加后的值
     * @param key
     * @param value
     * @param delta
     * @return
     */
    public Double zIncr(String key, String value, double delta) {
        return redisTemplate.opsForZSet().incrementScore(key, value, delta);
    }

    /**
     * 返回元素在集合的排名,有序集合是按照元素的score值由小到大排列
     * @param key
     * @param value
     * @return 0表示第一位
     */
    public Long zRank(String key, Object value) {
        return redisTemplate.opsForZSet().rank(key, value);
    }

    /**
     * 获取集合大小
     * @param key
     * @return
     */
    public Long zSize(String key) {
        return redisTemplate.opsForZSet().size(key);
    }

    /**
     * 获取key下的数据多少
     * @param key
     * @param time
     * @return
     */
    public Long getNum(String key, long time) {
        RedisAtomicLong counter = new RedisAtomicLong(key, this.redisTemplate.getConnectionFactory());
        counter.expire(time, TimeUnit.DAYS);
        Long amount = counter.incrementAndGet();
        return amount;
    }
}
